package com.five.years.common.utils;

import com.five.years.common.vo.DateVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String HHmmss = "HH:mm:ss";
    /**
     * 格式[yyyyMMdd]
     */
    public static String YYYYMMDD = "yyyyMMdd";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String MM_DD = "MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static String YYMMDD = "yyyy年MM月dd日";

    public static String MDD = "M月dd日";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM", "yyyyMMdd"};

    /**
     * 根据时间戳转换为时间
     *
     * @param time
     * @return
     */
    public static Date getDate(Long time) {
        if (time == null) {
            return null;
        }
        return new Date(time);
    }

    /**
     * 根据时间戳获取当前年纪，不足一岁为一岁。
     *
     * @param time
     * @return
     */
    public static String getAgeYear(Long time) {
        if (time == null) {
            return null;
        }
        Long year = (System.currentTimeMillis() - time) / 31536000000L + 1;
        return year + "岁";
    }

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String beforeDateTime() {
        Date nowDate = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(nowDate);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - 1);
        Date beforeDate = now.getTime();
        return DateFormatUtils.format(beforeDate, "yyyyMMdd");
    }

    public static final String beforeDate() {
        Date nowDate = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(nowDate);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - 1);
        Date beforeDate = now.getTime();
        return DateFormatUtils.format(beforeDate, YYYY_MM_DD);
    }

    public static final String afterDate() {
        Date nowDate = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(nowDate);
        now.set(Calendar.DATE, now.get(Calendar.DATE) + 1);
        Date beforeDate = now.getTime();
        return DateFormatUtils.format(beforeDate, YYYY_MM_DD);
    }

    public static final String previousDayTime() {
        Date nowDate = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(nowDate);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - 2);
        Date beforeDate = now.getTime();
        return DateFormatUtils.format(beforeDate, "yyyyMMdd");
    }

    public static final String previousDay() {
        Date nowDate = new Date();
        Calendar now = Calendar.getInstance();
        now.setTime(nowDate);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - 2);
        Date beforeDate = now.getTime();
        return DateFormatUtils.format(beforeDate, YYYY_MM_DD);
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 计算两个时间差
     */
    public static Long getDateDay(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        return day;
    }

    private static final String formYMDHMS = "yyyy-MM-dd HH:mm:ss";
    private static final String formYMD = "yyyy-MM-dd";
    private static final SimpleDateFormat staticFomat = new SimpleDateFormat(formYMDHMS);
    private static final SimpleDateFormat staticYMD = new SimpleDateFormat(formYMD);

    public static Date StringToDate(String date) {
        Date resultDate = null;
        try {
            resultDate = staticFomat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return resultDate;
    }

    public static String DateToString(Date date) {
        return staticYMD.format(date);
    }

    public static String stringToDate(Date date) {
        return staticFomat.format(date);
    }


    /**
     * 返回当前日期+时间 YYYY_MM_DD_HH_MM_SS
     *
     * @return 返回该日期的字符串格式
     */
    public static String getNowTimeByString(String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(new GregorianCalendar().getTime());

    }

    /**
     * @Author zhang
     * @Date 2020/4/9 0009
     * @Description 获取当天23：59：59的秒数
     */
    public static Integer getSecond(String endTime) {
        String nowTimeByString = getNowTimeByString(HHmmss);
        Date date = dateTime(HHmmss, nowTimeByString);
        Date endDate = dateTime(HHmmss, endTime);
        Long second = new Long((endDate.getTime() - date.getTime()) / 1000);
        return second.intValue();
    }

    /**
     * 得到几天前的时间
     *
     * @param d
     * @param day
     * @return
     */
    public static Date getDateBefore(Date d, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(d);
        now.set(Calendar.DATE, now.get(Calendar.DATE) - day);
        return now.getTime();
    }

    /**
     * 得到几天后的时间
     *
     * @param d
     * @param day
     * @return
     */
    public static Date getDateAfter(Date d, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(d);
        now.set(Calendar.DATE, now.get(Calendar.DATE) + day);
        return now.getTime();
    }

    public static List<String> getDateFor30List() {
        Calendar now = Calendar.getInstance();
        Date nowDate = new Date();
        List<String> dateFor30List = new ArrayList<>();
        for (int i = 30; i > 0; i--) {
            now.setTime(nowDate);
            now.set(Calendar.DATE, now.get(Calendar.DATE) - i);
            Date beforeDate = now.getTime();
            String date = DateFormatUtils.format(beforeDate, YYYY_MM_DD);
            dateFor30List.add(date);
        }
        return dateFor30List;
    }

    public static List<String> getDateFor12List() {
        Calendar now = Calendar.getInstance();
        Date nowDate = new Date();
        List<String> dateFor30List = new ArrayList<>();
        for (int i = 11; i >= 0; i--) {
            now.setTime(nowDate);
            now.set(Calendar.MONTH, now.get(Calendar.MONTH) - i);
            Date beforeDate = now.getTime();
            String date = DateFormatUtils.format(beforeDate, YYYY_MM);
            dateFor30List.add(date);
        }
        return dateFor30List;
    }

    /**
     * @param nowDate   要比较的时间
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return true在时间段内，false不在时间段内
     * @throws Exception
     */
    public static boolean hourMinuteBetween(String nowDate, String startDate, String endDate) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");

        Date now = format.parse(nowDate);
        Date start = format.parse(startDate);
        Date end = format.parse(endDate);

        long nowTime = now.getTime();
        long startTime = start.getTime();
        long endTime = end.getTime();

        return nowTime >= startTime && nowTime <= endTime;
    }

    /**
     * 获取年龄，1岁1个月1天
     *
     * @param date yyyy-MM-dd
     * @return
     */
    public static String getAgeDetail(String date) {
        //如果有空格
        int index = date.indexOf(" ");
        if (index != -1) {
            date = date.substring(0, index);
        }
        String[] data = date.split("-");
        Calendar birthday = new GregorianCalendar(Integer.valueOf(data[0]), Integer.valueOf(data[1]), Integer.valueOf(data[2]));
        Calendar now = Calendar.getInstance();
        int year = now.get(Calendar.YEAR) - birthday.get(Calendar.YEAR);
        StringBuffer tag = new StringBuffer();
        if (year <= 0) {
            year = 1;
        }
        if (year > 0) {
            tag.append(year + "岁");
        }
        return String.valueOf(tag);
    }

    /**
     * 获取特定时间的 毫秒数
     */
    public static Long getMiol() {
        Calendar ca = Calendar.getInstance();
        //失效的时间
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        long fl = ca.getTimeInMillis();
        return fl;
    }

    /**
     * @Author jiangfeng.zhu
     * @Description 获取年龄 岁月天
     * @Date 17:48 2020/11/20
     **/
    public static String getAge(Date date) {
        String nowDate = DateUtils.getDate();
        String ageDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, date);
        String[] nowDateList = nowDate.split("-");
        String[] ageDateList = ageDate.split("-");
        Integer year = Integer.valueOf(nowDateList[0]) - Integer.valueOf(ageDateList[0]);
        Integer month = Integer.valueOf(nowDateList[1]) - Integer.valueOf(ageDateList[1]);
        Integer day = Integer.valueOf(nowDateList[2]) - Integer.valueOf(ageDateList[2]);
        if (day < 0) {
            day = day + 31;
            month--;
        }
        if (month < 0) {
            month = month + 12;
            year--;
        }
        if (year >= 10) {
            return new StringBuilder().append(year).append("岁").toString();
        }
        if (year < 0) {
            return "-1";
        }
        return new StringBuilder().append(year).append("岁").append(month).append("月").append(day).append("天").toString();
    }


    public static Date parseStrToDate(String dateStr, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }


    public static String getMonthAfter(Date date, Integer expireMonth) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, expireMonth);
        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, cal.getTime());
    }


    /**
     * 获得当天1时零分零秒
     *
     * @return
     */
    public static Date initDateByDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        calendar.set(Calendar.HOUR_OF_DAY, 1);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    /**
     * 根据开始时间和结束时间返回时间段内的时间集合
     *
     * @param beginDate
     * @param endDate
     * @return List
     */
    public static List<Date> getDatesBetweenTwoDate(Date beginDate, Date endDate, int n) {
        List<Date> lDate = new ArrayList<Date>();
        lDate.add(beginDate);// 把开始时间加入集合
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(beginDate);
        boolean bContinue = true;
        while (bContinue) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            cal.add(Calendar.DAY_OF_MONTH, n);
            // 测试此日期是否在指定日期之后
            if (endDate.after(cal.getTime())) {
                lDate.add(cal.getTime());
            } else {
                break;
            }
        }
        lDate.add(endDate);// 把结束时间加入集合
        return lDate;
    }

    public static String getWeek(Date date) {
        String[] weeks = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (week_index < 0) {
            week_index = 0;
        }
        return weeks[week_index];
    }

    public static String getWeek2(Date date) {
        String[] weeks = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (week_index < 0) {
            week_index = 0;
        }
        return weeks[week_index];
    }

    public static List<String> getEveryDay(String startDate, String endDate) {
        List<Date> dateList = getDatesBetweenTwoDate(dateTime(YYYY_MM_DD, startDate), dateTime(YYYY_MM_DD, endDate), 1);
        Set<String> dayList = new HashSet<>();
        dateList.stream().forEach(date -> {
            dayList.add(DateToString(date));
        });

        return new ArrayList<>(dayList);
    }

    public static List<String> getEveryXDay(String startDate, String endDate, Integer fFrequencyDay) {
        List<Date> dateList = getDatesBetweenTwoDate(dateTime(YYYY_MM_DD, startDate), dateTime(YYYY_MM_DD, endDate), fFrequencyDay);
        Set<String> dayList = new HashSet<>();
        dateList.stream().forEach(date -> {
            dayList.add(DateToString(date));
        });
        return new ArrayList<>(dayList);
    }

    public static List<String> getEveryDayExcludeWeek(String startDate, String endDate, List<String> selectFrequency) {
        List<Date> dateList = getDatesBetweenTwoDate(dateTime(YYYY_MM_DD, startDate), dateTime(YYYY_MM_DD, endDate), 1);
        Set<String> dayList = new HashSet<>();
        dateList.stream().forEach(date -> {
            String week = getWeek2(date);
            if (selectFrequency.contains(week)) {
                dayList.add(DateToString(date));
            }
        });
        return new ArrayList<>(dayList);
    }

    public static List<String> getEveryDayExcludeDay(String startDate, String endDate, List<String> selectFrequency) {
        List<Date> dateList = getDatesBetweenTwoDate(dateTime(YYYY_MM_DD, startDate), dateTime(YYYY_MM_DD, endDate), 1);
        Set<String> dayList = new HashSet<>();
        dateList.stream().forEach(date -> {
            String dateStr = DateToString(date);
            String[] data = dateStr.split("-");
            if (selectFrequency.contains(data[2])) {
                dayList.add(dateStr);
            }
        });
        return new ArrayList<>(dayList);
    }

    /**
     * 获取年龄，1岁1个月1天
     *
     * @param date yyyy-MM-dd
     * @return
     */
    public static Integer getAge(String date) {
        //如果有空格
        int index = date.indexOf(" ");
        if (index != -1) {
            date = date.substring(0, index);
        }
        String[] data = date.split("-");
        Calendar birthday = new GregorianCalendar(Integer.valueOf(data[0]), Integer.valueOf(data[1]), Integer.valueOf(data[2]));
        Calendar now = Calendar.getInstance();
        int year = now.get(Calendar.YEAR) - birthday.get(Calendar.YEAR);
        return year;
    }

    /**
     * 获取当前时间所在周的周一和周日的日期时间
     *
     * @return
     */
    public static DateVO getWeekDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Calendar cal = Calendar.getInstance();
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayWeek == 1) {
            dayWeek = 8;
        }

        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);
        Date mondayDate = cal.getTime();
        String weekBegin = sdf.format(mondayDate);

        cal.add(Calendar.DATE, 4 + cal.getFirstDayOfWeek());
        Date sundayDate = cal.getTime();
        String weekEnd = sdf.format(sundayDate);

        DateVO dateVO = new DateVO();
        LinkedList<String> dayList = getEveryDayList(weekBegin, weekEnd);
        dateVO.setStartDate(DateUtils.parseStrToDate(weekBegin + " 00:00:00", DateUtils.YYYY_MM_DD_HH_MM_SS));
        dateVO.setEndDate(DateUtils.parseStrToDate(weekEnd + " 23:59:59", DateUtils.YYYY_MM_DD_HH_MM_SS));
        dateVO.setDayList(dayList);
        return dateVO;
    }

    public static LinkedList<String> getEveryDayList(String startDate, String endDate) {
        List<Date> dateList = getDatesBetweenTwoDate(dateTime(YYYY_MM_DD, startDate), dateTime(YYYY_MM_DD, endDate), 1);
        LinkedList<String> dayList = new LinkedList<>();
        dateList.stream().forEach(date -> {
            dayList.add(DateToString(date));
        });

        return dayList;
    }

    /**
     * 获取当前时间所在月的第一天和最后一天的日期时间
     *
     * @return
     */
    public static DateVO getMonthDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();

        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        String monthBegin = sdf.format(cal.getTime());

        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        String monthEnd = sdf.format(cal.getTime());

        DateVO dateVO = new DateVO();
        LinkedList<String> dayList = getEveryDayList(monthBegin, monthEnd);
        dateVO.setDayList(dayList);
        dateVO.setStartDate(DateUtils.parseStrToDate(monthBegin + " 00:00:00", DateUtils.YYYY_MM_DD_HH_MM_SS));
        dateVO.setEndDate(DateUtils.parseStrToDate(monthEnd + " 23:59:59", DateUtils.YYYY_MM_DD_HH_MM_SS));
        return dateVO;
    }

    public static List<String> getMonth(){
        String startDate = "2021-05-01 00:00:00";
        Date startTime = StringToDate(startDate);
        Date endTime = new Date();
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(startTime);
        List<String> monthList = new LinkedList<>();
        monthList.add("2021-05");

        boolean bContinue = true;
        while (bContinue) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            cal.add(Calendar.MONTH, 1);
            // 测试此日期是否在指定日期之后
            if (endTime.after(cal.getTime())) {
                monthList.add(parseDateToStr(DateUtils.YYYY_MM, cal.getTime()));
            } else {
                break;
            }
        }
        return monthList;
    }

    public static Date getDateTomorrow(Date d) {
        Date date = parseStrToDate(DateUtils.dateTime(new Date()) + " " + parseDateToStr(HHmmss, d), YYYY_MM_DD_HH_MM_SS);
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.DATE, now.get(Calendar.DATE) + 1);
        return now.getTime();
    }

}
